﻿namespace WinnerCMS.Common.Security
{
    using System;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.Threading;

    public static class UnicodeCharacterEncoder
    {
        private static char[][] characterValues;
        private static LowerCodeCharts currentLowerCodeChartSettings = LowerCodeCharts.None;
        private static LowerMidCodeCharts currentLowerMidCodeChartSettings = LowerMidCodeCharts.None;
        private static MidCodeCharts currentMidCodeChartSettings = MidCodeCharts.None;
        private static UpperCodeCharts currentUpperCodeChartSettings = UpperCodeCharts.None;
        private static UpperMidCodeCharts currentUpperMidCodeChartSettings = UpperMidCodeCharts.None;
        private static char[][] namedEntities;
        private static readonly ReaderWriterLockSlim SyncLock = new ReaderWriterLockSlim();
        private static readonly char[] UnicodeApostrophe = "&#39;".ToCharArray();
        private const char UnicodeReplacementCharacter = '�';
        private static readonly char[] UnicodeSpace = "&#32;".ToCharArray();
        private static readonly char[] XmlApostrophe = "&apos;".ToCharArray();

        private static void AcquireReadLock()
        {
            SyncLock.EnterReadLock();
        }

        private static void AcquireWriteLock()
        {
            SyncLock.EnterWriteLock();
        }

        private static void ApplyHtmlSpecificValues()
        {
            characterValues[60] = "lt".ToCharArray();
            characterValues[0x3e] = "gt".ToCharArray();
            characterValues[0x26] = "amp".ToCharArray();
            characterValues[0x22] = "quot".ToCharArray();
            characterValues[0x27] = "#39".ToCharArray();
        }

        internal static string HtmlAttributeEncode(string input)
        {
            return HtmlEncode(input, false, new MethodSpecificEncoder(HtmlAttributeTweak));
        }

        private static bool HtmlAttributeTweak(char input, out char[] output)
        {
            if (input == '\'')
            {
                output = UnicodeApostrophe;
                return true;
            }
            if (input == ' ')
            {
                output = UnicodeSpace;
                return true;
            }
            output = null;
            return false;
        }

        internal static string HtmlEncode(string input, bool useNamedEntities)
        {
            return HtmlEncode(input, useNamedEntities, null);
        }

        private static string HtmlEncode(string input, bool useNamedEntities, MethodSpecificEncoder encoderTweak)
        {
            if (string.IsNullOrEmpty(input))
            {
                return input;
            }
            if (characterValues == null)
            {
                InitialiseSafeList();
            }
            if (useNamedEntities && (namedEntities == null))
            {
                InitialiseNamedEntityList();
            }
            char[] chArray = input.ToCharArray();
            int length = 0;
            int num2 = chArray.Length;
            char[] chArray2 = new char[num2 * 10];
            AcquireReadLock();
            try
            {
                for (int i = 0; i < num2; i++)
                {
                    char c = chArray[i];
                    int index = chArray[i];
                    switch (index)
                    {
                        case 0xfffe:
                        case 0xffff:
                            chArray2[length++] = (char)0xfffd;
                            break;

                        default:
                            if (char.IsHighSurrogate(c))
                            {
                                if ((i + 1) == num2)
                                {
                                    chArray2[length++] = (char)0xfffd;
                                }
                                else
                                {
                                    char ch2 = chArray[i + 1];
                                    char ch3 = chArray[i + 1];
                                    if (!char.IsLowSurrogate(ch2))
                                    {
                                        chArray2[length++] = (char)0xfffd;
                                    }
                                    else
                                    {
                                        i++;
                                        long num5 = (0x10000 + ((index - 0xd800) * 0x400)) + (ch3 - 0xdc00);
                                        char[] chArray4 = SafeList.HashThenValueGenerator(num5);
                                        chArray2[length++] = '&';
                                        for (int j = 0; j < chArray4.Length; j++)
                                        {
                                            chArray2[length++] = chArray4[j];
                                        }
                                        chArray2[length++] = ';';
                                    }
                                }
                            }
                            else if (char.IsLowSurrogate(c))
                            {
                                chArray2[length++] = (char)0xfffd;
                            }
                            else
                            {
                                char[] chArray3;
                                if ((encoderTweak != null) && encoderTweak(c, out chArray3))
                                {
                                    for (int k = 0; k < chArray3.Length; k++)
                                    {
                                        chArray2[length++] = chArray3[k];
                                    }
                                }
                                else if (useNamedEntities && (namedEntities[index] != null))
                                {
                                    char[] chArray5 = namedEntities[index];
                                    chArray2[length++] = '&';
                                    for (int m = 0; m < chArray5.Length; m++)
                                    {
                                        chArray2[length++] = chArray5[m];
                                    }
                                    chArray2[length++] = ';';
                                }
                                else if (characterValues[index] != null)
                                {
                                    char[] chArray6 = characterValues[index];
                                    chArray2[length++] = '&';
                                    for (int n = 0; n < chArray6.Length; n++)
                                    {
                                        chArray2[length++] = chArray6[n];
                                    }
                                    chArray2[length++] = ';';
                                }
                                else
                                {
                                    chArray2[length++] = c;
                                }
                            }
                            break;
                    }
                }
            }
            finally
            {
                ReleaseReadLock();
            }
            return new string(chArray2, 0, length);
        }

        private static void InitialiseNamedEntityList()
        {
            AcquireWriteLock();
            try
            {
                if (namedEntities == null)
                {
                    namedEntities = new char[0x10000][];
                    namedEntities[160] = "nbsp".ToCharArray();
                    namedEntities[0xa1] = "iexcl".ToCharArray();
                    namedEntities[0xa2] = "cent".ToCharArray();
                    namedEntities[0xa3] = "pound".ToCharArray();
                    namedEntities[0xa4] = "curren".ToCharArray();
                    namedEntities[0xa5] = "yen".ToCharArray();
                    namedEntities[0xa6] = "brvbar".ToCharArray();
                    namedEntities[0xa7] = "sect".ToCharArray();
                    namedEntities[0xa8] = "uml".ToCharArray();
                    namedEntities[0xa9] = "copy".ToCharArray();
                    namedEntities[170] = "ordf".ToCharArray();
                    namedEntities[0xab] = "laquo".ToCharArray();
                    namedEntities[0xac] = "not".ToCharArray();
                    namedEntities[0xad] = "shy".ToCharArray();
                    namedEntities[0xae] = "reg".ToCharArray();
                    namedEntities[0xaf] = "macr".ToCharArray();
                    namedEntities[0xb0] = "deg".ToCharArray();
                    namedEntities[0xb1] = "plusmn".ToCharArray();
                    namedEntities[0xb2] = "sup2".ToCharArray();
                    namedEntities[0xb3] = "sup3".ToCharArray();
                    namedEntities[180] = "acute".ToCharArray();
                    namedEntities[0xb5] = "micro".ToCharArray();
                    namedEntities[0xb6] = "para".ToCharArray();
                    namedEntities[0xb7] = "middot".ToCharArray();
                    namedEntities[0xb8] = "cedil".ToCharArray();
                    namedEntities[0xb9] = "sup1".ToCharArray();
                    namedEntities[0xba] = "ordm".ToCharArray();
                    namedEntities[0xbb] = "raquo".ToCharArray();
                    namedEntities[0xbc] = "frac14".ToCharArray();
                    namedEntities[0xbd] = "frac12".ToCharArray();
                    namedEntities[190] = "frac34".ToCharArray();
                    namedEntities[0xbf] = "iquest".ToCharArray();
                    namedEntities[0xc0] = "Agrave".ToCharArray();
                    namedEntities[0xc1] = "Aacute".ToCharArray();
                    namedEntities[0xc2] = "Acirc".ToCharArray();
                    namedEntities[0xc3] = "Atilde".ToCharArray();
                    namedEntities[0xc4] = "Auml".ToCharArray();
                    namedEntities[0xc5] = "Aring".ToCharArray();
                    namedEntities[0xc6] = "AElig".ToCharArray();
                    namedEntities[0xc7] = "Ccedil".ToCharArray();
                    namedEntities[200] = "Egrave".ToCharArray();
                    namedEntities[0xc9] = "Eacute".ToCharArray();
                    namedEntities[0xca] = "Ecirc".ToCharArray();
                    namedEntities[0xcb] = "Euml".ToCharArray();
                    namedEntities[0xcc] = "Igrave".ToCharArray();
                    namedEntities[0xcd] = "Iacute".ToCharArray();
                    namedEntities[0xce] = "Icirc".ToCharArray();
                    namedEntities[0xcf] = "Iuml".ToCharArray();
                    namedEntities[0xd0] = "ETH".ToCharArray();
                    namedEntities[0xd1] = "Ntilde".ToCharArray();
                    namedEntities[210] = "Ograve".ToCharArray();
                    namedEntities[0xd3] = "Oacute".ToCharArray();
                    namedEntities[0xd4] = "Ocirc".ToCharArray();
                    namedEntities[0xd5] = "Otilde".ToCharArray();
                    namedEntities[0xd6] = "Ouml".ToCharArray();
                    namedEntities[0xd7] = "times".ToCharArray();
                    namedEntities[0xd8] = "Oslash".ToCharArray();
                    namedEntities[0xd9] = "Ugrave".ToCharArray();
                    namedEntities[0xda] = "Uacute".ToCharArray();
                    namedEntities[0xdb] = "Ucirc".ToCharArray();
                    namedEntities[220] = "Uuml".ToCharArray();
                    namedEntities[0xdd] = "Yacute".ToCharArray();
                    namedEntities[0xde] = "THORN".ToCharArray();
                    namedEntities[0xdf] = "szlig".ToCharArray();
                    namedEntities[0xe0] = "agrave".ToCharArray();
                    namedEntities[0xe1] = "aacute".ToCharArray();
                    namedEntities[0xe2] = "acirc".ToCharArray();
                    namedEntities[0xe3] = "atilde".ToCharArray();
                    namedEntities[0xe4] = "auml".ToCharArray();
                    namedEntities[0xe5] = "aring".ToCharArray();
                    namedEntities[230] = "aelig".ToCharArray();
                    namedEntities[0xe7] = "ccedil".ToCharArray();
                    namedEntities[0xe8] = "egrave".ToCharArray();
                    namedEntities[0xe9] = "eacute".ToCharArray();
                    namedEntities[0xea] = "ecirc".ToCharArray();
                    namedEntities[0xeb] = "euml".ToCharArray();
                    namedEntities[0xec] = "igrave".ToCharArray();
                    namedEntities[0xed] = "iacute".ToCharArray();
                    namedEntities[0xee] = "icirc".ToCharArray();
                    namedEntities[0xef] = "iuml".ToCharArray();
                    namedEntities[240] = "eth".ToCharArray();
                    namedEntities[0xf1] = "ntilde".ToCharArray();
                    namedEntities[0xf2] = "ograve".ToCharArray();
                    namedEntities[0xf3] = "oacute".ToCharArray();
                    namedEntities[0xf4] = "ocirc".ToCharArray();
                    namedEntities[0xf5] = "otilde".ToCharArray();
                    namedEntities[0xf6] = "ouml".ToCharArray();
                    namedEntities[0xf7] = "divide".ToCharArray();
                    namedEntities[0xf8] = "oslash".ToCharArray();
                    namedEntities[0xf9] = "ugrave".ToCharArray();
                    namedEntities[250] = "uacute".ToCharArray();
                    namedEntities[0xfb] = "ucirc".ToCharArray();
                    namedEntities[0xfc] = "uuml".ToCharArray();
                    namedEntities[0xfd] = "yacute".ToCharArray();
                    namedEntities[0xfe] = "thorn".ToCharArray();
                    namedEntities[0xff] = "yuml".ToCharArray();
                    namedEntities[0x152] = "OElig".ToCharArray();
                    namedEntities[0x153] = "oelig".ToCharArray();
                    namedEntities[0x160] = "Scaron".ToCharArray();
                    namedEntities[0x161] = "scaron".ToCharArray();
                    namedEntities[0x178] = "Yuml".ToCharArray();
                    namedEntities[0x192] = "fnof".ToCharArray();
                    namedEntities[710] = "circ".ToCharArray();
                    namedEntities[0x2dc] = "tilde".ToCharArray();
                    namedEntities[0x391] = "Alpha".ToCharArray();
                    namedEntities[0x392] = "Beta".ToCharArray();
                    namedEntities[0x393] = "Gamma".ToCharArray();
                    namedEntities[0x394] = "Delta".ToCharArray();
                    namedEntities[0x395] = "Epsilon".ToCharArray();
                    namedEntities[0x396] = "Zeta".ToCharArray();
                    namedEntities[0x397] = "Eta".ToCharArray();
                    namedEntities[920] = "Theta".ToCharArray();
                    namedEntities[0x399] = "Iota".ToCharArray();
                    namedEntities[0x39a] = "Kappa".ToCharArray();
                    namedEntities[0x39b] = "Lambda".ToCharArray();
                    namedEntities[0x39c] = "Mu".ToCharArray();
                    namedEntities[0x39d] = "Nu".ToCharArray();
                    namedEntities[0x39e] = "Xi".ToCharArray();
                    namedEntities[0x39f] = "Omicron".ToCharArray();
                    namedEntities[0x3a0] = "Pi".ToCharArray();
                    namedEntities[0x3a1] = "Rho".ToCharArray();
                    namedEntities[0x3a3] = "Sigma".ToCharArray();
                    namedEntities[0x3a4] = "Tau".ToCharArray();
                    namedEntities[0x3a5] = "Upsilon".ToCharArray();
                    namedEntities[0x3a6] = "Phi".ToCharArray();
                    namedEntities[0x3a7] = "Chi".ToCharArray();
                    namedEntities[0x3a8] = "Psi".ToCharArray();
                    namedEntities[0x3a9] = "Omega".ToCharArray();
                    namedEntities[0x3b1] = "alpha".ToCharArray();
                    namedEntities[0x3b2] = "beta".ToCharArray();
                    namedEntities[0x3b3] = "gamma".ToCharArray();
                    namedEntities[0x3b4] = "delta".ToCharArray();
                    namedEntities[0x3b5] = "epsilon".ToCharArray();
                    namedEntities[950] = "zeta".ToCharArray();
                    namedEntities[0x3b7] = "eta".ToCharArray();
                    namedEntities[0x3b8] = "theta".ToCharArray();
                    namedEntities[0x3b9] = "iota".ToCharArray();
                    namedEntities[0x3ba] = "kappa".ToCharArray();
                    namedEntities[0x3bb] = "lambda".ToCharArray();
                    namedEntities[0x3bc] = "mu".ToCharArray();
                    namedEntities[0x3bd] = "nu".ToCharArray();
                    namedEntities[0x3be] = "xi".ToCharArray();
                    namedEntities[0x3bf] = "omicron".ToCharArray();
                    namedEntities[960] = "pi".ToCharArray();
                    namedEntities[0x3c1] = "rho".ToCharArray();
                    namedEntities[0x3c2] = "sigmaf".ToCharArray();
                    namedEntities[0x3c3] = "sigma".ToCharArray();
                    namedEntities[0x3c4] = "tau".ToCharArray();
                    namedEntities[0x3c5] = "upsilon".ToCharArray();
                    namedEntities[0x3c6] = "phi".ToCharArray();
                    namedEntities[0x3c7] = "chi".ToCharArray();
                    namedEntities[0x3c8] = "psi".ToCharArray();
                    namedEntities[0x3c9] = "omega".ToCharArray();
                    namedEntities[0x3d1] = "thetasym".ToCharArray();
                    namedEntities[0x3d2] = "upsih".ToCharArray();
                    namedEntities[0x3d6] = "piv".ToCharArray();
                    namedEntities[0x2002] = "ensp".ToCharArray();
                    namedEntities[0x2003] = "emsp".ToCharArray();
                    namedEntities[0x2009] = "thinsp".ToCharArray();
                    namedEntities[0x200c] = "zwnj".ToCharArray();
                    namedEntities[0x200d] = "zwj".ToCharArray();
                    namedEntities[0x200e] = "lrm".ToCharArray();
                    namedEntities[0x200f] = "rlm".ToCharArray();
                    namedEntities[0x2013] = "ndash".ToCharArray();
                    namedEntities[0x2014] = "mdash".ToCharArray();
                    namedEntities[0x2018] = "lsquo".ToCharArray();
                    namedEntities[0x2019] = "rsquo".ToCharArray();
                    namedEntities[0x201a] = "sbquo".ToCharArray();
                    namedEntities[0x201c] = "ldquo".ToCharArray();
                    namedEntities[0x201d] = "rdquo".ToCharArray();
                    namedEntities[0x201e] = "bdquo".ToCharArray();
                    namedEntities[0x2020] = "dagger".ToCharArray();
                    namedEntities[0x2021] = "Dagger".ToCharArray();
                    namedEntities[0x2022] = "bull".ToCharArray();
                    namedEntities[0x2026] = "hellip".ToCharArray();
                    namedEntities[0x2030] = "permil".ToCharArray();
                    namedEntities[0x2032] = "prime".ToCharArray();
                    namedEntities[0x2033] = "Prime".ToCharArray();
                    namedEntities[0x2039] = "lsaquo".ToCharArray();
                    namedEntities[0x203a] = "rsaquo".ToCharArray();
                    namedEntities[0x203e] = "oline".ToCharArray();
                    namedEntities[0x2044] = "frasl".ToCharArray();
                    namedEntities[0x20ac] = "euro".ToCharArray();
                    namedEntities[0x2111] = "image".ToCharArray();
                    namedEntities[0x2118] = "weierp".ToCharArray();
                    namedEntities[0x211c] = "real".ToCharArray();
                    namedEntities[0x2122] = "trade".ToCharArray();
                    namedEntities[0x2135] = "alefsym".ToCharArray();
                    namedEntities[0x2190] = "larr".ToCharArray();
                    namedEntities[0x2191] = "uarr".ToCharArray();
                    namedEntities[0x2192] = "rarr".ToCharArray();
                    namedEntities[0x2193] = "darr".ToCharArray();
                    namedEntities[0x2194] = "harr".ToCharArray();
                    namedEntities[0x21b5] = "crarr".ToCharArray();
                    namedEntities[0x21d0] = "lArr".ToCharArray();
                    namedEntities[0x21d1] = "uArr".ToCharArray();
                    namedEntities[0x21d2] = "rArr".ToCharArray();
                    namedEntities[0x21d3] = "dArr".ToCharArray();
                    namedEntities[0x21d4] = "hArr".ToCharArray();
                    namedEntities[0x2200] = "forall".ToCharArray();
                    namedEntities[0x2202] = "part".ToCharArray();
                    namedEntities[0x2203] = "exist".ToCharArray();
                    namedEntities[0x2205] = "empty".ToCharArray();
                    namedEntities[0x2207] = "nabla".ToCharArray();
                    namedEntities[0x2208] = "isin".ToCharArray();
                    namedEntities[0x2209] = "notin".ToCharArray();
                    namedEntities[0x220b] = "ni".ToCharArray();
                    namedEntities[0x220f] = "prod".ToCharArray();
                    namedEntities[0x2211] = "sum".ToCharArray();
                    namedEntities[0x2212] = "minus".ToCharArray();
                    namedEntities[0x2217] = "lowast".ToCharArray();
                    namedEntities[0x221a] = "radic".ToCharArray();
                    namedEntities[0x221d] = "prop".ToCharArray();
                    namedEntities[0x221e] = "infin".ToCharArray();
                    namedEntities[0x2220] = "ang".ToCharArray();
                    namedEntities[0x2227] = "and".ToCharArray();
                    namedEntities[0x2228] = "or".ToCharArray();
                    namedEntities[0x2229] = "cap".ToCharArray();
                    namedEntities[0x222a] = "cup".ToCharArray();
                    namedEntities[0x222b] = "int".ToCharArray();
                    namedEntities[0x2234] = "there4".ToCharArray();
                    namedEntities[0x223c] = "sim".ToCharArray();
                    namedEntities[0x2245] = "cong".ToCharArray();
                    namedEntities[0x2248] = "asymp".ToCharArray();
                    namedEntities[0x2260] = "ne".ToCharArray();
                    namedEntities[0x2261] = "equiv".ToCharArray();
                    namedEntities[0x2264] = "le".ToCharArray();
                    namedEntities[0x2265] = "ge".ToCharArray();
                    namedEntities[0x2282] = "sub".ToCharArray();
                    namedEntities[0x2283] = "sup".ToCharArray();
                    namedEntities[0x2284] = "nsub".ToCharArray();
                    namedEntities[0x2286] = "sube".ToCharArray();
                    namedEntities[0x2287] = "supe".ToCharArray();
                    namedEntities[0x2295] = "oplus".ToCharArray();
                    namedEntities[0x2297] = "otimes".ToCharArray();
                    namedEntities[0x22a5] = "perp".ToCharArray();
                    namedEntities[0x22c5] = "sdot".ToCharArray();
                    namedEntities[0x2308] = "lceil".ToCharArray();
                    namedEntities[0x2309] = "rceil".ToCharArray();
                    namedEntities[0x230a] = "lfloor".ToCharArray();
                    namedEntities[0x230b] = "rfloor".ToCharArray();
                    namedEntities[0x2329] = "lang".ToCharArray();
                    namedEntities[0x232a] = "rang".ToCharArray();
                    namedEntities[0x25ca] = "loz".ToCharArray();
                    namedEntities[0x2660] = "spades".ToCharArray();
                    namedEntities[0x2663] = "clubs".ToCharArray();
                    namedEntities[0x2665] = "hearts".ToCharArray();
                    namedEntities[0x2666] = "diams".ToCharArray();
                }
            }
            finally
            {
                ReleaseWriteLock();
            }
        }

        private static void InitialiseSafeList()
        {
            AcquireWriteLock();
            try
            {
                if (characterValues == null)
                {
                    characterValues = SafeList.Generate(0xffff, new SafeList.GenerateSafeValue(SafeList.HashThenValueGenerator));
                    SafeList.PunchUnicodeThrough(ref characterValues, LowerCodeCharts.Default, LowerMidCodeCharts.None, MidCodeCharts.None, UpperMidCodeCharts.None, UpperCodeCharts.None);
                    ApplyHtmlSpecificValues();
                }
            }
            finally
            {
                ReleaseWriteLock();
            }
        }

        public static void MarkAsSafe(LowerCodeCharts lowerCodeCharts, LowerMidCodeCharts lowerMidCodeCharts, MidCodeCharts midCodeCharts, UpperMidCodeCharts upperMidCodeCharts, UpperCodeCharts upperCodeCharts)
        {
            if ((((lowerCodeCharts != currentLowerCodeChartSettings) || (lowerMidCodeCharts != currentLowerMidCodeChartSettings)) || ((midCodeCharts != currentMidCodeChartSettings) || (upperMidCodeCharts != currentUpperMidCodeChartSettings))) || (upperCodeCharts != currentUpperCodeChartSettings))
            {
                AcquireWriteLock();
                try
                {
                    if (characterValues == null)
                    {
                        characterValues = SafeList.Generate(0x10000, new SafeList.GenerateSafeValue(SafeList.HashThenValueGenerator));
                    }
                    SafeList.PunchUnicodeThrough(ref characterValues, lowerCodeCharts, lowerMidCodeCharts, midCodeCharts, upperMidCodeCharts, upperCodeCharts);
                    ApplyHtmlSpecificValues();
                    currentLowerCodeChartSettings = lowerCodeCharts;
                    currentLowerMidCodeChartSettings = lowerMidCodeCharts;
                    currentMidCodeChartSettings = midCodeCharts;
                    currentUpperMidCodeChartSettings = upperMidCodeCharts;
                    currentUpperCodeChartSettings = upperCodeCharts;
                }
                finally
                {
                    ReleaseWriteLock();
                }
            }
        }

        private static void ReleaseReadLock()
        {
            SyncLock.ExitReadLock();
        }

        private static void ReleaseWriteLock()
        {
            SyncLock.ExitWriteLock();
        }

        internal static string XmlAttributeEncode(string input)
        {
            return HtmlEncode(input, false, new MethodSpecificEncoder(XmlAttributeTweak));
        }

        private static bool XmlAttributeTweak(char input, out char[] output)
        {
            if (input == '\'')
            {
                output = XmlApostrophe;
                return true;
            }
            if (input == ' ')
            {
                output = UnicodeSpace;
                return true;
            }
            output = null;
            return false;
        }

        internal static string XmlEncode(string input)
        {
            return HtmlEncode(input, false, new MethodSpecificEncoder(XmlTweak));
        }

        private static bool XmlTweak(char input, out char[] output)
        {
            if (input == '\'')
            {
                output = XmlApostrophe;
                return true;
            }
            output = null;
            return false;
        }

        private delegate bool MethodSpecificEncoder(char input, out char[] output);
    }
}

